#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>

void runCmd(char** tab){
        /**
                struct timeval {
                    time_t      tv_sec; // Secondes
                    suseconds_t tv_usec; // Microsecondes
                }
        */
        struct rusage usage;
        long wallClockTime;
        long cpuTime;

        // Process id of the child process
        pid_t cpid;
        cpid = fork();

        if (cpid == -1) /* Failure */
        {
                perror("Child process creation failed!");
                exit(EXIT_FAILURE);
        }
        else if (cpid == 0) /* In the child process */
        {
                // Execute the given command in the child process
                execvp(tab[0], tab);
        }
        else  /* In the parent process */
        {
                int status;
                (void)waitpid(cpid, &status, 0);
       
                printf("\nCommand Statistics:\n");
                getrusage(RUSAGE_CHILDREN, &usage);
               
                // Wall Clock Time
                wallClockTime = (usage.ru_utime.tv_sec * 1000) + (usage.ru_utime.tv_usec / 1000);
                printf("Wall-clock time: %6ld millisecondes\n", wallClockTime);

                // CPU time
                cpuTime = (usage.ru_stime.tv_sec * 1000) + (usage.ru_stime.tv_usec / 1000);
                printf("CPU time: %6ld millisecondes\n", cpuTime);

                // Voluntary interruptions
                printf("# Voluntary interruptions: %ld\n", usage.ru_nvcsw);

                // Involuntary interruptions
                printf("# Involuntary interruptions: %ld\n", usage.ru_nivcsw);

                // Page defaults
                printf("# Page defaults: %ld\n", usage.ru_majflt);

                // Page reclaims
                printf("# Page reclaims: %ld\n", usage.ru_minflt);
        }
}

/**
 * Returns the number of occurrences of 'c' in 'str'.
 */
int charCount(char *str, char c)
{
	int count = 0;
	while (*str != '\0')
	{
		if (*str == c)
			count++;
		str++;
	}
	return count;
}

/**
 * Replace all occurrences of 'c' by 'rep' in 'str'.
 */
void charReplace(char *str, char c, char rep)
{
	while (*str != '\0')
	{
		if (*str == c)
			*str = rep;
		str++;
	}
}

int main(int argc, char** argv)
{
	char * cmd = NULL;
        size_t len = 0;
        ssize_t read; // Cmd length: Nb of chars read
  	char *cmdTokenized;
	int spaceCount;
	int i, run = 1;

  	for (;;) {
		printf("Log710H2014%%>");
		
		if (read = getline(&cmd, &len, stdin) != -1)
		{
			// Count spaces in the command
			spaceCount = charCount(cmd, ' ');

			// Allocate array for command parts: nb spaces + 2 (Last element is NULL)
			char *tabCmd[spaceCount + 2];

			// Tokenize the command and save parts into the tabCmd array
			i = 0;
			cmdTokenized = strtok (cmd," ");
			while (cmdTokenized != NULL) {
				if (cmdTokenized != "\n" && cmdTokenized != "\r" && cmdTokenized != "\n\r" && cmdTokenized != "\0")
					tabCmd[i] = cmdTokenized;
				cmdTokenized = strtok (NULL, " ");
				i++;
			}
			// Trim the New Line from the penultimate part of the command
			charReplace(tabCmd[i - 1], '\n', '\0');
			
			// Add the NULL element at the end
			tabCmd[i] = NULL;

			if (strcmp(tabCmd[0], "") != 0)
			{
				// Process command
				if(strcmp(tabCmd[0], "exit") == 0) {
					break;
				}
				else if(strcmp(tabCmd[0], "cd") == 0) {
					if (tabCmd[1] != NULL)
					{
						if (chdir(tabCmd[1]) == -1)
								printf("/**\\ Failed to change the current directory to '%s'!\n", tabCmd[1]);
					}
					else
						printf("/*\\ Usage: cd [directory]\n");
				}
				else {
					runCmd(tabCmd);
				}
			}
		}
		else
		{
			printf("/**\\ An error occurred!\n");
		}
  	}
	
	return 0;
}
